package com.yl.demo.utils;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

/**
 * 存放静态字符串
 */
public final class GSONUtil {
	public String toJson() {
		Gson gson = getGson();
		String json = gson.toJson(this);

		return json;
	}

	public static final Gson getGson() {
		return getGson("yyyy-MM-dd HH:mm:ss.SSS");
	}

	private static final Gson getGson(String dateFmt) {
		GsonBuilder builder = new GsonBuilder();

		// builder.registerTypeAdapterFactory(new TypeAdapterFactory() {
		//
		// public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
		// System.out.println(type.getType());
		// return new BaseBeanAdapter<T>();
		// }
		// });
		builder.registerTypeAdapter(Date.class, new DateAdapter());
		builder.registerTypeAdapter(Map.class, new MapAdapter());
		builder.setDateFormat(dateFmt);

		Gson gson = builder.create();
		return gson;
	}

	public static final Gson getGsonNoMapAdapter() {
		GsonBuilder builder = new GsonBuilder();

		builder.registerTypeAdapter(Date.class, new DateAdapter());
		builder.setDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

		Gson gson = builder.create();
		return gson;
	}

	public static final Gson getGson(final Class<?>... skipClass) {
		GsonBuilder builder = new GsonBuilder();
		if (skipClass != null && skipClass.length > 0) {
			ExclusionStrategy es = new ExclusionStrategy() {
				public boolean shouldSkipField(FieldAttributes f) {
					return false;
				}

				public boolean shouldSkipClass(Class<?> cls) {
					for (Class<?> skip : skipClass) {
						if (cls.equals(skip)) {
							return true;
						}
					}
					return false;
				}
			};
			builder.setExclusionStrategies(es);
		}
		builder.registerTypeAdapter(Date.class, new DateAdapter());
		builder.registerTypeAdapter(Map.class, new MapAdapter());
		builder.setDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		Gson gson = builder.create();
		return gson;
	}

	private static class DateFormat {
		private SimpleDateFormat sf1 = null;// yyyy-MM-dd;
		private SimpleDateFormat sf2 = null;// yyyy-MM-dd HH:mm:ss;
		private SimpleDateFormat sf3 = null;// yyyy-MM-dd HH:mm:ss.SSS;

		protected final SimpleDateFormat getSF(String val) {
			if (val.length() == 23) {
				if (sf3 == null) {
					sf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
				}
				return sf3;
			} else if (val.length() == 19) {
				if (sf2 == null) {
					sf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				}
				return sf2;
			} else if (val.length() == 10) {
				if (sf1 == null) {
					sf1 = new SimpleDateFormat("yyyy-MM-dd");
				}
				return sf1;
			}
			return null;
		}
	}

	// private static class BaseBeanAdapter<T> extends TypeAdapter<BaseBean> {
	// public JsonElement serialize(BaseBean bean, Type type, JsonSerializationContext context) {
	// return new JsonPrimitive(bean.toJSON().toString());
	// }
	// public void write(JsonWriter out, BaseBean value) throws IOException {
	// out.
	//
	// }
	// public BaseBean read(JsonReader in) throws IOException {
	// return null;
	// }
	// }

	private static class DateAdapter extends DateFormat implements JsonSerializer<Date>, JsonDeserializer<Date> {
		public Date deserialize(JsonElement ele, Type type, JsonDeserializationContext context) throws JsonParseException {
			if (ele == null) {
				return null;
			}
			String json = ele.getAsString();
			json = json.trim();
			SimpleDateFormat sf = getSF(json);
			if (sf == null) {
				return null;
			} else {
				try {
					return sf.parse(json);
				} catch (ParseException e) {
				}
			}
			return null;
		}

		public JsonElement serialize(Date date, Type type, JsonSerializationContext context) {
			SimpleDateFormat sf = getSF("yyyy-MM-dd HH:mm:ss.SSS");
			return new JsonPrimitive(sf.format(date));
		}
	}

	private static class MapAdapter extends DateFormat implements JsonDeserializer<TreeMap<String, Object>> {

		public TreeMap<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {
			TreeMap<String, Object> treeMap = new TreeMap<>();
			JsonObject jsonObject = json.getAsJsonObject();

			for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
				Object ot = entry.getValue();
				if (ot == null) {
					continue;
				}
				if (ot instanceof JsonPrimitive) {
					JsonPrimitive jp = (JsonPrimitive) ot;
					if (jp.isNumber()) {
						Number num = jp.getAsNumber();
						long longVal = num.longValue();
						double doubleVal = num.doubleValue();
						if (longVal == doubleVal) {
							if (longVal == ((int) longVal)) {
								treeMap.put(entry.getKey(), (int) longVal);
							} else if (longVal == ((byte) longVal)) {
								treeMap.put(entry.getKey(), (byte) longVal);
							} else {
								treeMap.put(entry.getKey(), longVal);
							}
						} else if (doubleVal == ((float) doubleVal)) {
							treeMap.put(entry.getKey(), (float) doubleVal);
						} else {
							treeMap.put(entry.getKey(), num);
						}
					} else {
						String str = jp.getAsString();
						if (str.length() == 23) {// 疑似日期
							try {
								Date date = getSF(str).parse(str);
								treeMap.put(entry.getKey(), date);
								continue;
							} catch (Exception e) {
							}
						}
						treeMap.put(entry.getKey(), str);
					}
					continue;
				}
				if (ot instanceof JsonElement) {
					treeMap.put(entry.getKey(), deserialize((JsonElement) ot, typeOfT, context));
				} else {
					treeMap.put(entry.getKey(), ot);
				}
			}
			return treeMap;
		}

	}

	// private static class NumberAdapter extends DateFormat implements JsonDeserializer<Number> {
	//
	// public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
	// if (json == null) {
	// return null;
	// }
	// if (json instanceof JsonPrimitive) {
	// JsonPrimitive jp = (JsonPrimitive) json;
	// if (jp.isNumber()) {
	// Number num = jp.getAsNumber();
	// long longVal = num.longValue();
	// double doubleVal = num.doubleValue();
	// if (longVal == doubleVal) {
	// if (longVal == ((int) longVal)) {
	// return (int) longVal;
	// } else if (longVal == ((byte) longVal)) {
	// return (byte) longVal;
	// } else {
	// return longVal;
	// }
	// } else if (doubleVal == ((float) doubleVal)) {
	// return (float) doubleVal;
	// } else {
	// return num;
	// }
	// }
	// }
	// return null;
	// }
	//
	// }

}